package org.molamil.acto.types {
	import org.molamil.acto.core.parsers.ParserError;
	
	/**
	 * Type parser expecting the value passed when <code>parse()</code> to be 
	 * "Date compatible". These values should be in ISO 8601 format (YYYY-MM-DD hh:mm:ss)
	 * or in the native Flash <code>Date.format()</code> format (e.g. "Sat Nov 30 1974").
	 * 
	 * @example The following code will parse "1979-10-21 09:00" into a new date
	 * and will trace "Sun Oct 21 09:00:00 GMT+0200 1979":
	 * <listing version="3.0" >
	 * var parser:AbstractTypeParser = new DateTypeParser();
	 * var d:Date = parser.parse("1979-10-21 09:00");
	 * trace(d);
	 * </listing>
	 * 
	 * @author Jorge Hernandez
	 * @see Date
	 */
	public class DateTypeParser extends AbstractTypeParser {
		
		
		// CONSTANTS
		
		/**
		 * @inheritDoc
		 */
		public static const PRIORITY:uint = 100;
		
		/**
		 * @inheritDoc
		 */
		public static const TYPE:Class = Date;
		
		
		// PROTECTED METHODS
		
		/**
		 * Returns a <code>Date</code> object created from the value passed or 
		 * throws an <code>Error</code> if value does not contain any 
		 * representation that can be parsed into a <code>Date</code>
		 * 
		 * <p>There are 2 date formats supported:</p>
		 * <ul>
		 * 	<li>ISO 8601 format, e.g. "1979-10-21T09:00". The use of a blank space
		 * 	to separate date and time is also supported: "1979-10-21 09:00".<br />
		 * 	Note:
		 * 		<ul>
		 * 	 		<li>The extended-format is used, in which the date elements are to
		 * 	 		be separated by a hyphen, and the time elements by a colon.</li>
		 * 	 		<li>Week dates are not supported.</li>
		 * 	 		<li>Decimal formats are not supported.</li>
		 * 	 		<li>Time zones are not supported.</li>
		 * 	 		<li>At least year, month and day have to be provided: YYYY-MM-DD.<br /><br /></li>
		 * 	 	</ul>
		 * 	</li>
		 * 	<li><p>Native Flash <code>Date.parse()</code> format. The following is extracted from the the Flash documentation:</p>
		 * 	
		 * 	<p>A string representation of a date, which conforms to the format for the output of
		 * 	<code>Date.toString()</code>. The date format for the output of <code>Date.toString()</code> is:</p>
		 * 	<pre>
		 * 	     Day Mon DD HH:MM:SS TZD YYYY
		 * 	</pre>
		 * 	<p>For example: </p>
		 * 	<pre>
		 * 	     Wed Apr 12 15:30:17 GMT-0700 2006
		 * 	</pre>
		 * 	<p>The Time Zone Designation (TZD) is always in the form <code>GMT-HHMM</code> or <code>UTC-HHMM</code> indicating the 
		 * 	     hour and minute offset relative to Greenwich Mean Time (GMT), which is now also called universal time (UTC).
		 * 	     The year month and day terms can be separated by a forward slash (<code>/</code>) or by spaces, but never by a
		 * 	     dash (<code>-</code>). Other supported formats include the following (you can include partial representations of these 
		 * 	     formats; that is, just the month, day, and year):</p>
		 * 	     
		 *  <pre>
		 *       MM/DD/YYYY HH:MM:SS TZD
		 *       HH:MM:SS TZD Day Mon/DD/YYYY 
		 *       Mon DD YYYY HH:MM:SS TZD
		 *       Day Mon DD HH:MM:SS TZD YYYY
		 *       Day DD Mon HH:MM:SS TZD YYYY
		 *       Mon/DD/YYYY HH:MM:SS TZD
		 *       YYYY/MM/DD HH:MM:SS TZD
		 *  </pre></li>
		 * </ul>
		 * 
		 * @param value <code>String</code> value to test
		 * @return <code>Date</code> representation of the value passed
		 * @throws org.molamil.acto.core.errors.ParserError The value can't
		 * 	be converted to a <code>Date</code>
		 * @see Date
		 */
		override protected function doParse(value:String):* {
			
			if (value == null)
				throw new ParserError("ERROR: value is null and cannot be parsed " +
					"into a Date");
			
			var pattern:RegExp = /^(\d{4})-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])((( |T)([01][0-9]|2[0-4]))?(:[0-5][0-9])?(:[0-5][0-9])?)?$/;
			
			var millis:Number = Date.parse(value);
			
			if (!isNaN(millis)) {
				return new Date(millis);
			} else if(pattern.test(value)) {
				return parseIso8601Date(value);
			} else {
				throw new ParserError("ERROR: '" + value + "' cannot be parsed " +
					"into a Date");
			}
			
		}
		
		
		// PRIVATE METHODS
		
		private function parseIso8601Date(value:String):Date {
			
			var date:Date;
			
			var parts:Array = value.split(value.indexOf("T") != -1 ? "T" : " ");
			var datePart:String = parts[0];
			var dateParts:Array = datePart.split("-");
			var timePart:String = parts[1];
			var timeParts:Array = new Array();
			if (timePart != null)
				timeParts = timePart.split(":");
			
			date = new Date(dateParts[0], dateParts[1] - 1, dateParts[2], 
							timeParts[0] != undefined ? timeParts[0] : null, 
							timeParts[1] != undefined ? timeParts[1] : null,
							timeParts[2] != undefined ? timeParts[2] : null);
			
			return date;
			
		}
		
		
	}
	
}
